package inteligenciaartificial;

import java.util.ArrayList;

public class Mutador {
    
    //probabilidad de mutacion minima
    private static double pm= 0;
    //probabilidad de mutacion maxima
    private static double pM= 0;
    //incremento "lambda" de probabilidad de mutacion
    private static double lambda= 0;
   
     /**
     * Constructor para mutador por temperatura ascendente/descendente
     */
    public static void inicializar(double probabilidadMinima, double probabilidadMaxima, double lambda){
        pm= probabilidadMinima;
        pM= probabilidadMaxima;
        Mutador.lambda= lambda;
    }
    
    public static Individuo[] mutarPorTemperaturaAscendente(Generacion generacion, int cantidad){
        //chequear si fue corectamente inicializado
        if(pm==0|| pM==0||lambda==0) return null;

        //calcular la probabilidad de mutación para la generacion actual
        double prob = pm + (lambda* (generacion.getNroDeGeneracion()-1));
        if(prob > pM) prob= pM;
        
        return mutarConProbabilidad(cantidad, prob, generacion);
    }
    
       public static Individuo[] mutarPorTemperaturaDescendente(Generacion generacion, int cantidad){
        //chequear si fue corectamente inicializado
        if(pm==0|| pM==0||lambda==0) return null;

        //calcular la probabilidad de mutación para la generacion actual
        double prob = pM - (lambda* (generacion.getNroDeGeneracion()-1));
        if(prob < pm) prob= pm;
       
        return mutarConProbabilidad(cantidad, prob, generacion);
    }
    
    /**
     * @return la probabilidad de mutación minima
     */
    public static double getProbabilidadMinima() {
        return pm;
    }

    /**
     * @return la probabilidad de mutacion maxima
     */
    public static double getProbabilidadMaxima() {
        return pM;
    }

    /**
     * @return el valor de "lambda"
     */
    public static double getLambda() {
        return lambda;
    }

    private static Individuo[] mutarConProbabilidad(int cantidad, double probabilidad, Generacion generacion) {
        //contador para controlar que no se quede iterando infinitamente si no consigue la cantidad de individuos solicitada
        Individuo[] mutados = new Individuo[cantidad];
       
        for(int i=0;i<mutados.length;i++){

            int indiceIndAMutar= (int) (Math.random()* Settings.totalPoblacion);
            Individuo individuoMutado= Mutador.mutarIndividuo(generacion.getIndividuoNumero(indiceIndAMutar),probabilidad);
            mutados[i]=individuoMutado;
        }
        
        return mutados;
    }
    
    public static Individuo mutarIndividuo(Individuo individuo, double probabilidadMutacion){
        if(individuo==null) return null;
        Individuo individuoMutado= null;
        do{
            int[] genesMutados = individuo.getGenes().clone();
            for (int i=0;i<Individuo.CantidadDeGenes;i++){
                double random= Math.random();
                if(random<=probabilidadMutacion){
                    Intervalo valoresLimite= IndividuoManager.getIntervaloParaPosicion(i);
                    genesMutados[i]= (int) (valoresLimite.getMinimo() + (Math.random() * valoresLimite.amplitud()));
                }
            }
            individuoMutado= new Individuo(genesMutados);

         }while(! IndividuoManager.individuoCumpleRestricciones(individuoMutado));
        
        individuoMutado.setNroGeneracionPadre(individuo.getNroGeneracion());
        individuoMutado.setNroIndividuoPadre(individuo.getNroIndividuo());
        individuoMutado.setOperadorGenerador(Individuo.Operador.Mutacion);
        return individuoMutado;
    }
        
}
